{
 "cells": [
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-11T06:29:11.689304Z",
     "start_time": "2025-05-11T06:29:08.913157Z"
    }
   },
   "cell_type": "code",
   "source": [
    "%matplotlib inline\n",
    "import os\n",
    "import torch\n",
    "import torchvision\n",
    "from d2l import torch as d2l"
   ],
   "id": "3185698bd0e021fc",
   "outputs": [],
   "execution_count": 1
  },
  {
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-11T06:44:18.273236Z",
     "start_time": "2025-05-11T06:29:13.361098Z"
    }
   },
   "cell_type": "code",
   "source": [
    "#@save\n",
    "d2l.DATA_HUB['voc2012'] = (d2l.DATA_URL + 'VOCtrainval_11-May-2012.tar',\n",
    "                           '4e443f8a2eca6b1dac8a6c57641b67dd40621a49')\n",
    "\n",
    "voc_dir = d2l.download_extract('voc2012', 'VOCdevkit/VOC2012')"
   ],
   "id": "9f59487bd9cc8874",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading ../data\\VOCtrainval_11-May-2012.tar from http://d2l-data.s3-accelerate.amazonaws.com/VOCtrainval_11-May-2012.tar...\n"
     ]
    },
    {
     "ename": "ChunkedEncodingError",
     "evalue": "(\"Connection broken: TimeoutError(10060, '由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。', None, 10060, None)\", TimeoutError(10060, '由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。', None, 10060, None))",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mTimeoutError\u001B[0m                              Traceback (most recent call last)",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\urllib3\\response.py:754\u001B[0m, in \u001B[0;36mHTTPResponse._error_catcher\u001B[1;34m(self)\u001B[0m\n\u001B[0;32m    753\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 754\u001B[0m     \u001B[38;5;28;01myield\u001B[39;00m\n\u001B[0;32m    756\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m SocketTimeout \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[0;32m    757\u001B[0m     \u001B[38;5;66;03m# FIXME: Ideally we'd like to include the url in the ReadTimeoutError but\u001B[39;00m\n\u001B[0;32m    758\u001B[0m     \u001B[38;5;66;03m# there is yet no clean way to get at it from this context.\u001B[39;00m\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\urllib3\\response.py:879\u001B[0m, in \u001B[0;36mHTTPResponse._raw_read\u001B[1;34m(self, amt, read1)\u001B[0m\n\u001B[0;32m    878\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_error_catcher():\n\u001B[1;32m--> 879\u001B[0m     data \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_fp_read\u001B[49m\u001B[43m(\u001B[49m\u001B[43mamt\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mread1\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mread1\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m fp_closed \u001B[38;5;28;01melse\u001B[39;00m \u001B[38;5;124mb\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m    880\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m amt \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;129;01mand\u001B[39;00m amt \u001B[38;5;241m!=\u001B[39m \u001B[38;5;241m0\u001B[39m \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m data:\n\u001B[0;32m    881\u001B[0m         \u001B[38;5;66;03m# Platform-specific: Buggy versions of Python.\u001B[39;00m\n\u001B[0;32m    882\u001B[0m         \u001B[38;5;66;03m# Close the connection when no data is returned\u001B[39;00m\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m    887\u001B[0m         \u001B[38;5;66;03m# not properly close the connection in all cases. There is\u001B[39;00m\n\u001B[0;32m    888\u001B[0m         \u001B[38;5;66;03m# no harm in redundantly calling close.\u001B[39;00m\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\urllib3\\response.py:862\u001B[0m, in \u001B[0;36mHTTPResponse._fp_read\u001B[1;34m(self, amt, read1)\u001B[0m\n\u001B[0;32m    860\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m    861\u001B[0m     \u001B[38;5;66;03m# StringIO doesn't like amt=None\u001B[39;00m\n\u001B[1;32m--> 862\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_fp\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mread\u001B[49m\u001B[43m(\u001B[49m\u001B[43mamt\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;28;01mif\u001B[39;00m amt \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;28;01melse\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_fp\u001B[38;5;241m.\u001B[39mread()\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\http\\client.py:463\u001B[0m, in \u001B[0;36mHTTPResponse.read\u001B[1;34m(self, amt)\u001B[0m\n\u001B[0;32m    462\u001B[0m b \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mbytearray\u001B[39m(amt)\n\u001B[1;32m--> 463\u001B[0m n \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mreadinto\u001B[49m\u001B[43m(\u001B[49m\u001B[43mb\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    464\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mmemoryview\u001B[39m(b)[:n]\u001B[38;5;241m.\u001B[39mtobytes()\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\http\\client.py:507\u001B[0m, in \u001B[0;36mHTTPResponse.readinto\u001B[1;34m(self, b)\u001B[0m\n\u001B[0;32m    504\u001B[0m \u001B[38;5;66;03m# we do not use _safe_read() here because this may be a .will_close\u001B[39;00m\n\u001B[0;32m    505\u001B[0m \u001B[38;5;66;03m# connection, and the user is reading more bytes than will be provided\u001B[39;00m\n\u001B[0;32m    506\u001B[0m \u001B[38;5;66;03m# (for example, reading in 1k chunks)\u001B[39;00m\n\u001B[1;32m--> 507\u001B[0m n \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mfp\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mreadinto\u001B[49m\u001B[43m(\u001B[49m\u001B[43mb\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    508\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m n \u001B[38;5;129;01mand\u001B[39;00m b:\n\u001B[0;32m    509\u001B[0m     \u001B[38;5;66;03m# Ideally, we would raise IncompleteRead if the content-length\u001B[39;00m\n\u001B[0;32m    510\u001B[0m     \u001B[38;5;66;03m# wasn't satisfied, but it might break compatibility.\u001B[39;00m\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\socket.py:716\u001B[0m, in \u001B[0;36mSocketIO.readinto\u001B[1;34m(self, b)\u001B[0m\n\u001B[0;32m    715\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 716\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_sock\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrecv_into\u001B[49m\u001B[43m(\u001B[49m\u001B[43mb\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    717\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m timeout:\n",
      "\u001B[1;31mTimeoutError\u001B[0m: [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。",
      "\nThe above exception was the direct cause of the following exception:\n",
      "\u001B[1;31mProtocolError\u001B[0m                             Traceback (most recent call last)",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\requests\\models.py:816\u001B[0m, in \u001B[0;36mResponse.iter_content.<locals>.generate\u001B[1;34m()\u001B[0m\n\u001B[0;32m    815\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 816\u001B[0m     \u001B[38;5;28;01myield from\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mraw\u001B[38;5;241m.\u001B[39mstream(chunk_size, decode_content\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[0;32m    817\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m ProtocolError \u001B[38;5;28;01mas\u001B[39;00m e:\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\urllib3\\response.py:1066\u001B[0m, in \u001B[0;36mHTTPResponse.stream\u001B[1;34m(self, amt, decode_content)\u001B[0m\n\u001B[0;32m   1065\u001B[0m \u001B[38;5;28;01mwhile\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m is_fp_closed(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_fp) \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;28mlen\u001B[39m(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_decoded_buffer) \u001B[38;5;241m>\u001B[39m \u001B[38;5;241m0\u001B[39m:\n\u001B[1;32m-> 1066\u001B[0m     data \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mread\u001B[49m\u001B[43m(\u001B[49m\u001B[43mamt\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mamt\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdecode_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mdecode_content\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m   1068\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m data:\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\urllib3\\response.py:955\u001B[0m, in \u001B[0;36mHTTPResponse.read\u001B[1;34m(self, amt, decode_content, cache_content)\u001B[0m\n\u001B[0;32m    953\u001B[0m         \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_decoded_buffer\u001B[38;5;241m.\u001B[39mget(amt)\n\u001B[1;32m--> 955\u001B[0m data \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_raw_read\u001B[49m\u001B[43m(\u001B[49m\u001B[43mamt\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    957\u001B[0m flush_decoder \u001B[38;5;241m=\u001B[39m amt \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;129;01mor\u001B[39;00m (amt \u001B[38;5;241m!=\u001B[39m \u001B[38;5;241m0\u001B[39m \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m data)\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\urllib3\\response.py:908\u001B[0m, in \u001B[0;36mHTTPResponse._raw_read\u001B[1;34m(self, amt, read1)\u001B[0m\n\u001B[0;32m    901\u001B[0m     \u001B[38;5;28;01melif\u001B[39;00m read1 \u001B[38;5;129;01mand\u001B[39;00m (\n\u001B[0;32m    902\u001B[0m         (amt \u001B[38;5;241m!=\u001B[39m \u001B[38;5;241m0\u001B[39m \u001B[38;5;129;01mand\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m data) \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mlength_remaining \u001B[38;5;241m==\u001B[39m \u001B[38;5;28mlen\u001B[39m(data)\n\u001B[0;32m    903\u001B[0m     ):\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m    906\u001B[0m         \u001B[38;5;66;03m# `http.client.HTTPResponse`, so we close it here.\u001B[39;00m\n\u001B[0;32m    907\u001B[0m         \u001B[38;5;66;03m# See https://github.com/python/cpython/issues/113199\u001B[39;00m\n\u001B[1;32m--> 908\u001B[0m         \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_fp\u001B[38;5;241m.\u001B[39mclose()\n\u001B[0;32m    910\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m data:\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\contextlib.py:137\u001B[0m, in \u001B[0;36m_GeneratorContextManager.__exit__\u001B[1;34m(self, typ, value, traceback)\u001B[0m\n\u001B[0;32m    136\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 137\u001B[0m     \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mgen\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mthrow\u001B[49m\u001B[43m(\u001B[49m\u001B[43mtyp\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mvalue\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mtraceback\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    138\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mStopIteration\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m exc:\n\u001B[0;32m    139\u001B[0m     \u001B[38;5;66;03m# Suppress StopIteration *unless* it's the same exception that\u001B[39;00m\n\u001B[0;32m    140\u001B[0m     \u001B[38;5;66;03m# was passed to throw().  This prevents a StopIteration\u001B[39;00m\n\u001B[0;32m    141\u001B[0m     \u001B[38;5;66;03m# raised inside the \"with\" statement from being suppressed.\u001B[39;00m\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\urllib3\\response.py:781\u001B[0m, in \u001B[0;36mHTTPResponse._error_catcher\u001B[1;34m(self)\u001B[0m\n\u001B[0;32m    780\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (HTTPException, \u001B[38;5;167;01mOSError\u001B[39;00m) \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[1;32m--> 781\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m ProtocolError(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mConnection broken: \u001B[39m\u001B[38;5;132;01m{\u001B[39;00me\u001B[38;5;132;01m!r}\u001B[39;00m\u001B[38;5;124m\"\u001B[39m, e) \u001B[38;5;28;01mfrom\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21;01me\u001B[39;00m\n\u001B[0;32m    783\u001B[0m \u001B[38;5;66;03m# If no exception is thrown, we should avoid cleaning up\u001B[39;00m\n\u001B[0;32m    784\u001B[0m \u001B[38;5;66;03m# unnecessarily.\u001B[39;00m\n",
      "\u001B[1;31mProtocolError\u001B[0m: (\"Connection broken: TimeoutError(10060, '由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。', None, 10060, None)\", TimeoutError(10060, '由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。', None, 10060, None))",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001B[1;31mChunkedEncodingError\u001B[0m                      Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[2], line 5\u001B[0m\n\u001B[0;32m      1\u001B[0m \u001B[38;5;66;03m#@save\u001B[39;00m\n\u001B[0;32m      2\u001B[0m d2l\u001B[38;5;241m.\u001B[39mDATA_HUB[\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mvoc2012\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;241m=\u001B[39m (d2l\u001B[38;5;241m.\u001B[39mDATA_URL \u001B[38;5;241m+\u001B[39m \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mVOCtrainval_11-May-2012.tar\u001B[39m\u001B[38;5;124m'\u001B[39m,\n\u001B[0;32m      3\u001B[0m                            \u001B[38;5;124m'\u001B[39m\u001B[38;5;124m4e443f8a2eca6b1dac8a6c57641b67dd40621a49\u001B[39m\u001B[38;5;124m'\u001B[39m)\n\u001B[1;32m----> 5\u001B[0m voc_dir \u001B[38;5;241m=\u001B[39m \u001B[43md2l\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdownload_extract\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mvoc2012\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mVOCdevkit/VOC2012\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\d2l\\torch.py:3243\u001B[0m, in \u001B[0;36mdownload_extract\u001B[1;34m(name, folder)\u001B[0m\n\u001B[0;32m   3239\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m\u001B[38;5;250m \u001B[39m\u001B[38;5;21mdownload_extract\u001B[39m(name, folder\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m):\n\u001B[0;32m   3240\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124;03m\"\"\"Download and extract a zip/tar file.\u001B[39;00m\n\u001B[0;32m   3241\u001B[0m \n\u001B[0;32m   3242\u001B[0m \u001B[38;5;124;03m    Defined in :numref:`sec_utils`\"\"\"\u001B[39;00m\n\u001B[1;32m-> 3243\u001B[0m     fname \u001B[38;5;241m=\u001B[39m \u001B[43mdownload\u001B[49m\u001B[43m(\u001B[49m\u001B[43mname\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m   3244\u001B[0m     base_dir \u001B[38;5;241m=\u001B[39m os\u001B[38;5;241m.\u001B[39mpath\u001B[38;5;241m.\u001B[39mdirname(fname)\n\u001B[0;32m   3245\u001B[0m     data_dir, ext \u001B[38;5;241m=\u001B[39m os\u001B[38;5;241m.\u001B[39mpath\u001B[38;5;241m.\u001B[39msplitext(fname)\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\d2l\\torch.py:3221\u001B[0m, in \u001B[0;36mdownload\u001B[1;34m(url, folder, sha1_hash)\u001B[0m\n\u001B[0;32m   3219\u001B[0m r \u001B[38;5;241m=\u001B[39m requests\u001B[38;5;241m.\u001B[39mget(url, stream\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, verify\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[0;32m   3220\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m \u001B[38;5;28mopen\u001B[39m(fname, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124mwb\u001B[39m\u001B[38;5;124m'\u001B[39m) \u001B[38;5;28;01mas\u001B[39;00m f:\n\u001B[1;32m-> 3221\u001B[0m     f\u001B[38;5;241m.\u001B[39mwrite(\u001B[43mr\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcontent\u001B[49m)\n\u001B[0;32m   3222\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m fname\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\requests\\models.py:899\u001B[0m, in \u001B[0;36mResponse.content\u001B[1;34m(self)\u001B[0m\n\u001B[0;32m    897\u001B[0m         \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_content \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m\n\u001B[0;32m    898\u001B[0m     \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m--> 899\u001B[0m         \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_content \u001B[38;5;241m=\u001B[39m \u001B[38;5;124;43mb\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mjoin\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43miter_content\u001B[49m\u001B[43m(\u001B[49m\u001B[43mCONTENT_CHUNK_SIZE\u001B[49m\u001B[43m)\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;124mb\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m    901\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_content_consumed \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;01mTrue\u001B[39;00m\n\u001B[0;32m    902\u001B[0m \u001B[38;5;66;03m# don't need to release the connection; that's been handled by urllib3\u001B[39;00m\n\u001B[0;32m    903\u001B[0m \u001B[38;5;66;03m# since we exhausted the data.\u001B[39;00m\n",
      "File \u001B[1;32m~\\anaconda3\\envs\\d2l\\lib\\site-packages\\requests\\models.py:818\u001B[0m, in \u001B[0;36mResponse.iter_content.<locals>.generate\u001B[1;34m()\u001B[0m\n\u001B[0;32m    816\u001B[0m     \u001B[38;5;28;01myield from\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mraw\u001B[38;5;241m.\u001B[39mstream(chunk_size, decode_content\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m)\n\u001B[0;32m    817\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m ProtocolError \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[1;32m--> 818\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m ChunkedEncodingError(e)\n\u001B[0;32m    819\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m DecodeError \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[0;32m    820\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m ContentDecodingError(e)\n",
      "\u001B[1;31mChunkedEncodingError\u001B[0m: (\"Connection broken: TimeoutError(10060, '由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。', None, 10060, None)\", TimeoutError(10060, '由于连接方在一段时间后没有正确答复或连接的主机没有反应，连接尝试失败。', None, 10060, None))"
     ]
    }
   ],
   "execution_count": 2
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "#@save\n",
    "def read_voc_images(voc_dir, is_train=True):\n",
    "    \"\"\"读取所有VOC图像并标注\"\"\"\n",
    "    txt_fname = os.path.join(voc_dir, 'ImageSets', 'Segmentation',\n",
    "                             'train.txt' if is_train else 'val.txt')\n",
    "    mode = torchvision.io.image.ImageReadMode.RGB\n",
    "    with open(txt_fname, 'r') as f:\n",
    "        images = f.read().split()\n",
    "    features, labels = [], []\n",
    "    for i, fname in enumerate(images):\n",
    "        features.append(torchvision.io.read_image(os.path.join(\n",
    "            voc_dir, 'JPEGImages', f'{fname}.jpg')))\n",
    "        labels.append(torchvision.io.read_image(os.path.join(\n",
    "            voc_dir, 'SegmentationClass' ,f'{fname}.png'), mode))\n",
    "    return features, labels\n",
    "\n",
    "train_features, train_labels = read_voc_images(voc_dir, True)"
   ],
   "id": "a1a140a72d5eca2e"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "n = 5\n",
    "imgs = train_features[0:n] + train_labels[0:n]\n",
    "imgs = [img.permute(1,2,0) for img in imgs]\n",
    "d2l.show_images(imgs, 2, n);"
   ],
   "id": "ec57245150033f9f"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "#@save\n",
    "VOC_COLORMAP = [[0, 0, 0], [128, 0, 0], [0, 128, 0], [128, 128, 0],\n",
    "                [0, 0, 128], [128, 0, 128], [0, 128, 128], [128, 128, 128],\n",
    "                [64, 0, 0], [192, 0, 0], [64, 128, 0], [192, 128, 0],\n",
    "                [64, 0, 128], [192, 0, 128], [64, 128, 128], [192, 128, 128],\n",
    "                [0, 64, 0], [128, 64, 0], [0, 192, 0], [128, 192, 0],\n",
    "                [0, 64, 128]]\n",
    "\n",
    "#@save\n",
    "VOC_CLASSES = ['background', 'aeroplane', 'bicycle', 'bird', 'boat',\n",
    "               'bottle', 'bus', 'car', 'cat', 'chair', 'cow',\n",
    "               'diningtable', 'dog', 'horse', 'motorbike', 'person',\n",
    "               'potted plant', 'sheep', 'sofa', 'train', 'tv/monitor']"
   ],
   "id": "d59b70dd5f6c98bf"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "#@save\n",
    "def voc_colormap2label():\n",
    "    \"\"\"构建从RGB到VOC类别索引的映射\"\"\"\n",
    "    colormap2label = torch.zeros(256 ** 3, dtype=torch.long)\n",
    "    for i, colormap in enumerate(VOC_COLORMAP):\n",
    "        colormap2label[\n",
    "            (colormap[0] * 256 + colormap[1]) * 256 + colormap[2]] = i\n",
    "    return colormap2label\n",
    "\n",
    "#@save\n",
    "def voc_label_indices(colormap, colormap2label):\n",
    "    \"\"\"将VOC标签中的RGB值映射到它们的类别索引\"\"\"\n",
    "    colormap = colormap.permute(1, 2, 0).numpy().astype('int32')\n",
    "    idx = ((colormap[:, :, 0] * 256 + colormap[:, :, 1]) * 256\n",
    "           + colormap[:, :, 2])\n",
    "    return colormap2label[idx]"
   ],
   "id": "5a0e16a6f8a74ad1"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "y = voc_label_indices(train_labels[0], voc_colormap2label())\n",
    "y[105:115, 130:140], VOC_CLASSES[1]"
   ],
   "id": "c8a855ab77c614ea"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "#@save\n",
    "def voc_rand_crop(feature, label, height, width):\n",
    "    \"\"\"随机裁剪特征和标签图像\"\"\"\n",
    "    rect = torchvision.transforms.RandomCrop.get_params(\n",
    "        feature, (height, width))\n",
    "    feature = torchvision.transforms.functional.crop(feature, *rect)\n",
    "    label = torchvision.transforms.functional.crop(label, *rect)\n",
    "    return feature, label\n",
    "\n",
    "imgs = []\n",
    "for _ in range(n):\n",
    "    imgs += voc_rand_crop(train_features[0], train_labels[0], 200, 300)\n",
    "\n",
    "imgs = [img.permute(1, 2, 0) for img in imgs]\n",
    "d2l.show_images(imgs[::2] + imgs[1::2], 2, n);"
   ],
   "id": "ac247e770ac35d34"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "#@save\n",
    "class VOCSegDataset(torch.utils.data.Dataset):\n",
    "    \"\"\"一个用于加载VOC数据集的自定义数据集\"\"\"\n",
    "\n",
    "    def __init__(self, is_train, crop_size, voc_dir):\n",
    "        self.transform = torchvision.transforms.Normalize(\n",
    "            mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n",
    "        self.crop_size = crop_size\n",
    "        features, labels = read_voc_images(voc_dir, is_train=is_train)\n",
    "        self.features = [self.normalize_image(feature)\n",
    "                         for feature in self.filter(features)]\n",
    "        self.labels = self.filter(labels)\n",
    "        self.colormap2label = voc_colormap2label()\n",
    "        print('read ' + str(len(self.features)) + ' examples')\n",
    "\n",
    "    def normalize_image(self, img):\n",
    "        return self.transform(img.float() / 255)\n",
    "\n",
    "    def filter(self, imgs):\n",
    "        return [img for img in imgs if (\n",
    "            img.shape[1] >= self.crop_size[0] and\n",
    "            img.shape[2] >= self.crop_size[1])]\n",
    "\n",
    "    def __getitem__(self, idx):\n",
    "        feature, label = voc_rand_crop(self.features[idx], self.labels[idx],\n",
    "                                       *self.crop_size)\n",
    "        return (feature, voc_label_indices(label, self.colormap2label))\n",
    "\n",
    "    def __len__(self):\n",
    "        return len(self.features)"
   ],
   "id": "12c2e8a166240837"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "crop_size = (320, 480)\n",
    "voc_train = VOCSegDataset(True, crop_size, voc_dir)\n",
    "voc_test = VOCSegDataset(False, crop_size, voc_dir)"
   ],
   "id": "97f0da5ab8adb681"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "batch_size = 64\n",
    "train_iter = torch.utils.data.DataLoader(voc_train, batch_size, shuffle=True,\n",
    "                                    drop_last=True,\n",
    "                                    num_workers=d2l.get_dataloader_workers())\n",
    "for X, Y in train_iter:\n",
    "    print(X.shape)\n",
    "    print(Y.shape)\n",
    "    break"
   ],
   "id": "74026166d0f6df07"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": [
    "#@save\n",
    "def load_data_voc(batch_size, crop_size):\n",
    "    \"\"\"加载VOC语义分割数据集\"\"\"\n",
    "    voc_dir = d2l.download_extract('voc2012', os.path.join(\n",
    "        'VOCdevkit', 'VOC2012'))\n",
    "    num_workers = d2l.get_dataloader_workers()\n",
    "    train_iter = torch.utils.data.DataLoader(\n",
    "        VOCSegDataset(True, crop_size, voc_dir), batch_size,\n",
    "        shuffle=True, drop_last=True, num_workers=num_workers)\n",
    "    test_iter = torch.utils.data.DataLoader(\n",
    "        VOCSegDataset(False, crop_size, voc_dir), batch_size,\n",
    "        drop_last=True, num_workers=num_workers)\n",
    "    return train_iter, test_iter"
   ],
   "id": "912f7e3fcece7b91"
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": "",
   "id": "d1eb908067e12405"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.22"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
